package com.eight.cloud.redisson.config;

import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.codec.JsonJacksonCodec;
import org.redisson.config.Config;
import org.redisson.spring.cache.RedissonSpringCacheManager;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.cache.CacheManager;
import org.springframework.context.annotation.Bean;

import static com.eight.cloud.core.global.constant.NumConstant.ONE;
import static com.eight.cloud.core.global.constant.NumConstant.ZERO;

/**
 * @ClassName: RedissonConfig
 * @Author: TXC
 * @Date: 2024-10-01 15:11
 **/
@Slf4j
@AutoConfiguration
public class RedissonConfig {

    @Value("${spring.redisson.mode:single}")
    private String mode;
    /**
     * 仅仅用于sentinel模式。
     */
    @Value("${spring.redisson.masterName:}")
    private String masterName;

    /**
     * 单机模式：必须以redis://开头
     * 集群模式：多个redis地址，以逗号分隔，同时每个节点前必须以redis://开头。
     * 哨兵模式：多个redis地址，以逗号分隔，同时每个节点前必须以redis://开头。
     * 主从模式：多个redis地址，以逗号分隔，第一个为主节点，其余为从节点。同时每个节点前必须以redis://开头。
     */
    @Value("#{'${spring.redisson.address}'.split(',')}")
    private String[] address;

    @Value("${spring.redisson.username:}")
    private String username;

    @Value("${spring.redisson.password:}")
    private String password;
    /**
     * 数据库默认0
     */
    @Value("${spring.redisson.database:0}")
    private Integer database;

    @Value("${spring.redisson.retryAttempts:1500}")
    private Integer retryAttempts;

    @Value("${spring.redisson.retryInterval:3}")
    private Integer retryInterval;

    @Value("${spring.redisson.timeout:3000}")
    private Integer timeout;

    private static final String SINGLE = "single";
    private static final String CLUSTER = "cluster";
    private static final String SENTINEL = "sentinel";
    private static final String MASTER_SLAVE = "master-slave";

    /**
     * 单机模式配置
     */
    @Bean(destroyMethod = "shutdown")
    @ConditionalOnMissingBean
    public RedissonClient redissonClient() {
        try {
            Config config = new Config();
            if (SINGLE.equals(mode)) {
                config.useSingleServer().setDatabase(database).setUsername(StrUtil.emptyToNull(username)).setPassword(StrUtil.emptyToNull(password)).setAddress(address[ZERO])
                        .setRetryAttempts(retryAttempts).setRetryInterval(retryInterval).setTimeout(timeout);
            } else if (CLUSTER.equals(mode)) {
                //集群模式不支持多个数据库概念，默认db 0
                config.useClusterServers().setUsername(StrUtil.emptyToNull(username)).setPassword(StrUtil.emptyToNull(password)).addNodeAddress(address)
                        .setRetryAttempts(retryAttempts).setRetryInterval(retryInterval).setTimeout(timeout);
            } else if (SENTINEL.equals(mode)) {
                config.useSentinelServers().setDatabase(database).setUsername(StrUtil.emptyToNull(username)).setPassword(StrUtil.emptyToNull(password))
                        .setMasterName(masterName).addSentinelAddress(address)
                        .setRetryAttempts(retryAttempts).setRetryInterval(retryInterval).setTimeout(timeout);
            } else if (MASTER_SLAVE.equals(mode)) {
                if (address.length == 1) {
                    throw new IllegalArgumentException("redis.redisson.address MUST have multiple redis addresses for master-slave mode.");
                }
                String[] slaveAddresses = new String[address.length - ONE];
                System.arraycopy(address, ONE, slaveAddresses, ZERO, slaveAddresses.length);
                config.useMasterSlaveServers().setDatabase(database).setUsername(StrUtil.emptyToNull(username)).setPassword(StrUtil.emptyToNull(password))
                        .setMasterAddress(address[ZERO]).addSlaveAddress(slaveAddresses)
                        .setRetryAttempts(retryAttempts).setRetryInterval(retryInterval).setTimeout(timeout);
            } else {
                throw new IllegalArgumentException(mode);
            }
            config.setCodec(new JsonJacksonCodec());
            config.setConnectionListener(new RedisConnectionListener());
            return Redisson.create(config);
        } catch (Exception e) {
            log.error("==========Redisson配置失败: {}", e.getMessage());
            return null;
        }
    }

    /**
     * 构建Redisson缓存管理器
     */
    @Bean
    public CacheManager cacheManager(RedissonClient redisson) {
        return new RedissonSpringCacheManager(redisson);
    }
}
